package com.polaris.live.common.cacha

import com.polaris.live.common.AppModule
import com.polaris.live.common.constant.CacheConst
import com.polaris.live.common.ext.autoDp
import com.polaris.live.common.resp.AppLandingPageVo
import com.polaris.live.common.resp.ConfigPostResp
import com.polaris.live.common.resp.ConfigPreResp
import com.polaris.live.common.util.JsonUtils
import com.tencent.mmkv.MMKV
import kotlin.math.min

/**
 * mmkv缓存
 *
 * @author Created by 半仙 on 2023/7/31/031 18:03
 */
object CacheUtil {

    @Volatile
    private var lastServerTime: Long? = null

    @Volatile
    private var lastClientTime: Long? = null

    /**
     * 获取客户端维护的服务器时间戳
     *
     * 逻辑：  本次请求的时间戳  -  上次请求的时间戳  +  服务端返回的时间戳
     */
    fun getServerTime(): Long {
        return if (getLastServerTime() == 0L) {
            System.currentTimeMillis()
        } else {
            System.currentTimeMillis() - getLastClientTime() + getLastServerTime()
        }
    }

    /**
     * 获取服务端返回的时间戳
     */
    private fun getLastServerTime(): Long {
        return lastServerTime ?: let {
            val kv = MMKV.mmkvWithID(CacheConst.APP)
            kv.decodeLong(CacheConst.SERVICE_TIME, 0L).apply {
                lastServerTime = this
            }
        }
    }

    /**
     * 获取上次网络请求的时间戳
     */
    private fun getLastClientTime(): Long {
        return lastClientTime ?: let {
            val kv = MMKV.mmkvWithID(CacheConst.APP)
            kv.decodeLong(CacheConst.LAST_TIME, System.currentTimeMillis()).apply {
                lastClientTime = this
            }
        }
    }

    fun setLastServerTime(lastServerTime: Long) {
        CacheUtil.lastServerTime = lastServerTime
        val lastClientTime = System.currentTimeMillis()
        CacheUtil.lastClientTime = lastClientTime

        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.SERVICE_TIME, lastServerTime)
        kv.encode(CacheConst.LAST_TIME, lastClientTime)
    }

    /**
     * 存uuid
     */
    fun getuuid(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeString(CacheConst.uuid, "")
    }

    fun setuuid(uuid: String) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.uuid, uuid)
    }

    /**
     * 存config/pre里的东西
     */
    fun saveConfigPre(configPre: ConfigPreResp) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.CONFIG_PRE, configPre)
    }

    fun getConfigPreFromKV(): ConfigPreResp? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeParcelable(CacheConst.CONFIG_PRE, ConfigPreResp::class.java)
    }

    /**
     * 存config/post里的东西 有设备唯一码 配置 服务端配置版本什么的
     */
    fun saveConfigPost(configPost: ConfigPostResp) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.CONFIG_POST, configPost)
    }

    fun getConfigPostFromKV(): ConfigPostResp? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeParcelable(CacheConst.CONFIG_POST, ConfigPostResp::class.java)
    }

    /**
     * 存储uniqueId
     */
    fun setUniqueId(uniqueId: String) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.uniqueId, uniqueId)
    }

    fun getUniqueId(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeString(CacheConst.uniqueId)
    }

    fun saveDebugUrl(url: String) {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        kv.encode(CacheConst.SERVER_KEY_DEBUG_URL, url)
    }

    fun getDebugUrlFromKV(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        return kv.decodeString(CacheConst.SERVER_KEY_DEBUG_URL)
    }

    fun saveDebugEnv(env: String) {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        kv.encode(CacheConst.SERVER_KEY_DEBUG_ENV, env)
    }

    fun getDebugEnvFromKV(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        return kv.decodeString(CacheConst.SERVER_KEY_DEBUG_ENV)
    }

    fun saveCurrentUrl(url: String) {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        kv.encode(CacheConst.SERVER_KEY_CURRENT_URL, url)
    }

    fun getCurrentUrlFromKV(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        return kv.decodeString(CacheConst.SERVER_KEY_CURRENT_URL)
    }

    fun saveMainUrl(url: String) {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        kv.encode(CacheConst.SERVER_KEY_MAIN_URL, url)
    }

    fun getMainUrlFromKV(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        return kv.decodeString(CacheConst.SERVER_KEY_MAIN_URL)
    }

    fun saveDomainUrls(domainUrls: Set<String>) {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        kv.encode(CacheConst.SERVER_KEY_DOMAIN, domainUrls)
    }

    fun getDomainUrlsFromKV(): Set<String>? {
        val kv = MMKV.mmkvWithID(CacheConst.SERVER)
        return kv.decodeStringSet(CacheConst.SERVER_KEY_DOMAIN)
    }

    fun saveLastAreaCodeAndPhoneNumber(areaCode: String, phoneNumber: String) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.PHONE_NUMBER, "$areaCode|$phoneNumber")
    }

    fun getLastPhoneNumber(): Pair<String, String>? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        val phoneNumber = kv.decodeString(CacheConst.PHONE_NUMBER)
        return if (phoneNumber.isNullOrEmpty()) {
            null
        } else {
            val split = phoneNumber.split("|")
            if (split.size != 2) {
                null
            } else {
                split[0] to split[1]
            }
        }
    }

    fun saveLastGmail(gmail: String) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.LAST_GMAIL, gmail)
    }

    fun getLastGmail(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeString(CacheConst.LAST_GMAIL)
    }

    /**
     * 取申诉使用邮箱
     */
    fun getAppealEmail(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeString(CacheConst.APPEAL_EMAIL, "")
    }

    /**
     * 存申诉使用邮箱
     */
    fun setAppealEmail(email: String) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.APPEAL_EMAIL, email)
    }

    /**
     * 取反馈使用邮箱
     */
    fun getFeedbackEmail(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeString(CacheConst.FEEDBACK_EMAIL, "")
    }

    /**
     * 存反馈使用邮箱
     */
    fun setFeedbackEmail(email: String) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.FEEDBACK_EMAIL, email)
    }

    /**
     * 存点赞数
     */
    fun setLastLikeNum(userId: String, num: Long) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode("${CacheConst.LIKE}${userId}", num)
    }

    /**
     * 取点赞数
     */
    fun getLikeNum(userId: String): Long {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeLong("${CacheConst.LIKE}${userId}")
    }

    /**
     * 存点赞的最近时间戳
     */
    fun setLikeDate(userId: String, likeDate: Long) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode("${CacheConst.LIKE_DATE}${userId}", likeDate)
    }

    /**
     * 取点赞的最近时间戳
     */
    fun getLikeDate(userId: String): Long {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeLong("${CacheConst.LIKE_DATE}${userId}", 0L)
    }

    /**
     * 设置过申请通知权限
     */
    fun setApplyNoticePermission() {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.FIRST_APPLY_NOTICE, true)
    }

    /**
     * 获取是否申请过通知权限
     */
    fun isFirstApplyNoticePermission(): Boolean {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeBool(CacheConst.FIRST_APPLY_NOTICE, false)
    }

    /**
     * 存版本更新时间戳
     */
    fun setUpdateVersionTime(version: String) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode("Date$version", System.currentTimeMillis())
    }

    /**
     * 取版本更新时间戳
     */
    fun getUpdateVersionTime(version: String): Long {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeLong("Date$version", 0L)
    }

    /**
     * 存版本更新时间戳
     */
    fun setMainUpdateVersionTime(version: String) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode("Date${UserManager.getUser().userId}$version", System.currentTimeMillis())
    }

    /**
     * 取版本更新时间戳
     */
    fun getMainUpdateVersionTime(version: String): Long {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeLong("Date${UserManager.getUser().userId}$version", 0L)
    }

    /**
     * 存版本更新弹窗
     */
    fun setUpdateVersion(version: String, status: Boolean) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(version, status)
    }

    /**
     * 取版本更新弹窗
     */
    fun getUpdateVersion(version: String): Boolean {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeBool(version, false)
    }

    /**
     * 首页存版本更新弹窗
     */
    fun setMainUpdateVersion(version: String, status: Boolean) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode("${UserManager.getUser().userId}${version}", status)
    }

    /**
     * 首页取版本更新弹窗
     */
    fun getMainUpdateVersion(version: String): Boolean {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeBool("${UserManager.getUser().userId}${version}", false)
    }

    /**
     * 存首页页面
     */
    fun setAppLandingPage(landingPage: AppLandingPageVo) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.LANDING_PAGE, JsonUtils.toJson(landingPage))
    }

    /**
     * 取首页页面
     */
    fun getAppLandingPage(): AppLandingPageVo? {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeString(CacheConst.LANDING_PAGE)?.let {
            JsonUtils.fromJson<AppLandingPageVo>(it)
        }
    }

    /**
     * 存进入过的游戏
     */
    fun setEnterDot(gameId: Long) {
        val data = getEnterDot()
        if (data.none { it == gameId }) {
            data.add(gameId)
            val kv = MMKV.mmkvWithID(CacheConst.APP)
            JsonUtils.toJson(data)
                .apply { kv.encode("${UserManager.getUserId()}${CacheConst.ENTER_FISHING}", this) }
        }
    }

    /**
     * 取进入过的游戏
     */
    fun getEnterDot(): MutableList<Long> {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        val data = kv.decodeString("${UserManager.getUserId()}${CacheConst.ENTER_FISHING}")
        return data?.let { JsonUtils.fromJson<MutableList<Long>>(it) } ?: mutableListOf()
    }

    /**
     * 存上次弹窗时间
     */
    fun setLastGameWinPopTime(time: Long) {
        setManyGameWinPopTime(time)
    }

    /**
     * 取上次弹窗时间
     */
    fun getLastGameWinPopTime(): Long {
        val list = getManyGameWinPopTime()
        return list.lastOrNull() ?: 0
    }

    /**
     * 存多次弹窗时间
     */
    private fun setManyGameWinPopTime(time: Long) {
        val list = getManyGameWinPopTime().apply { add(time) }.takeLast(2)
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(
            "${UserManager.getUserId()}${CacheConst.LAST_MANY_GAMEWIN_POPTIME}",
            JsonUtils.toJson(list)
        )
    }

    /**
     * 取多次弹窗时间
     */
    fun getManyGameWinPopTime(): MutableList<Long> {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        val data =
            kv.decodeString("${UserManager.getUserId()}${CacheConst.LAST_MANY_GAMEWIN_POPTIME}")
        return data?.let { JsonUtils.fromJson<MutableList<Long>>(it) } ?: mutableListOf()
    }

    /**
     * 保存ip国家
     */
    fun saveIpCountry(ipCountry: String) {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        kv.encode(CacheConst.IP_COUNTRY, ipCountry)
    }

    /**
     * 获取缓存的ip国家
     */
    fun getIpCountry(): String? {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        return kv.decodeString(CacheConst.IP_COUNTRY)
    }

    /**
     * 保存dma选项
     */
    fun saveDmaUserSelected(agree: Boolean) {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        kv.encode(CacheConst.DMA_SELECTED, agree.toString())
    }

    /**
     * 获取dma的选项
     */
    fun getDmaUserSelected(): Boolean? {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        return kv.decodeString(CacheConst.DMA_SELECTED)?.toBooleanStrictOrNull()
    }

    fun saveDmaDialogShowed() {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        kv.encode(CacheConst.LAST_DMA_SHOWED, "true")
    }

    /**
     * 获取是否显示过dma弹窗
     */
    fun getDmaDialogShowed(): Boolean? {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        return kv.decodeString(CacheConst.LAST_DMA_SHOWED)?.toBooleanStrictOrNull()
    }

    fun savePhoneNumberShowed() {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        kv.encode(CacheConst.PHONE_NUMBER_SHOWED, "true")
    }

    /**
     *是否应该显示手机号
     */
    fun isPhoneNumberShowed(): Boolean? {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        return kv.decodeString(CacheConst.PHONE_NUMBER_SHOWED)?.toBooleanStrictOrNull()
    }

    fun saveVerifyCode(number: String, verifyCodeType: Int) {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        kv.encode(
            genSentVerifyCodeKey(number, verifyCodeType),
            getServerTime().toString(),
            (SENT_EXPIRE_TIME / 1000).toInt()
        )
    }

    fun deleteVerifyCode(number: String, verifyCodeType: Int) {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        kv.remove(genSentVerifyCodeKey(number, verifyCodeType))
    }

    /**
     * 是否发送过验证码
     */
    fun isSentVerifyCode(number: String, verifyCodeType: Int): Long {
        val kv = MMKV.mmkvWithID(CacheConst.TEMP)
        val lastTime = kv.decodeString(genSentVerifyCodeKey(number, verifyCodeType))
            ?.toLongOrNull()
            ?: return 0L

        val duration = SENT_EXPIRE_TIME
        return min(duration - (getServerTime() - lastTime), duration)
    }

    private fun genSentVerifyCodeKey(number: String, verifyCodeType: Int): String {
        return CacheConst.VERIFY_CODE_CACHE + ":" + number + ":" + verifyCodeType
    }

    private const val SENT_EXPIRE_TIME = 60 * 1000L

    /**
     * 存本地configVersion版本号
     */
    fun saveConfigVersion(version: Int) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.CONFIG_VERSION + ":" + AppModule.getAppVersion(), version)
    }

    fun getConfigVersionFromKV(): Int {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeInt(CacheConst.CONFIG_VERSION + ":" + AppModule.getAppVersion(), -1)
    }

    /**
     * TrAddr
     */
    fun saveTrAddr(left: Int, top: Int) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.GAME_CALL_TR_ADDR, "$left,$top")
    }

    fun getTrAddrFromKV(): IntArray {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return (kv.decodeString(CacheConst.GAME_CALL_TR_ADDR, "0,${250.autoDp}") ?: "0,${250.autoDp}").split(",")
            .map { it.toInt() }
            .toIntArray()
    }

    /**
     * FloatingViewAddr
     */
    fun saveFloatingViewAddr(left: Int, top: Int) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode(CacheConst.FLOATINGVIEW_TR_ADDR, "$left,$top")
    }

    fun getFloatingViewAddrFromKV(): IntArray {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return (kv.decodeString(CacheConst.FLOATINGVIEW_TR_ADDR, "0,${250.autoDp}") ?: "0,${250.autoDp}").split(",")
            .map { it.toInt() }
            .toIntArray()
    }

    /**
     * saveFloatingViewTips 保存是否提示过最小化功能上线
     */
    fun saveFloatingViewTips(pd: Boolean) {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        kv.encode( "${UserManager.getUserId()}${CacheConst.FLOATINGVIEW_TIPS}", pd)
    }

    fun getFloatingViewTipsFromKV(): Boolean {
        val kv = MMKV.mmkvWithID(CacheConst.APP)
        return kv.decodeBool("${UserManager.getUserId()}${CacheConst.FLOATINGVIEW_TIPS}", false)
    }
}